package com.rpp.factory;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Map;

/**
 * @Description
 * @Author rpp
 * @Date 2020/6/27 6:34 下午
 */
public class ClassPathApplicationContext {

    private String resource;

    public ClassPathApplicationContext(String resource) {
        this.resource = resource;
    }

    public void build(Map<String, Object> map) {

        //加载配置文件成字节流
        InputStream resourceAsStream = BeanFactory.class.getClassLoader().getResourceAsStream(resource);
        try {
            Document document = new SAXReader().read(resourceAsStream);
            Element rootElement = document.getRootElement();
            List<Element> list = rootElement.selectNodes("//bean");
            for (Element element : list) {
                //解析id 和 class 全限定名称
                String id = element.attributeValue("id");
                String className = element.attributeValue("class");
                //通过反射实例化对象 并放入集合中
                Class<?> aClass = Class.forName(className);
                Object object = aClass.newInstance();
                map.put(id, object);
            }

            List<Element> propertyList = rootElement.selectNodes("//property");
            for (Element element : propertyList) {
                //获取属性名称及对应的class
                String name = element.attributeValue("name");
                String ref = element.attributeValue("ref");

                //找出父节点
                Element parent = element.getParent();
                String id = parent.attributeValue("id");
                //通过父节点的ID 获取对应的实例对象
                Object obj = map.get(id);
                //获取所有方法
                Method[] methods = obj.getClass().getMethods();
                for (Method method : methods) {
                    //判断如果有对应的set方法，设置对应的值
                    if (method.getName().equalsIgnoreCase("set" + name)) {
                        method.invoke(obj, map.get(ref));
                    }
                }
                //重新放入容器集合中
                map.put(id, obj);
            }
        } catch (DocumentException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }
}
